package com.example.webgobang.component;

import com.example.webgobang.model.match.MatchResponse;
import com.example.webgobang.model.domin.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.Queue;

@Slf4j
@Component
public class Matcher {
    private final Queue<User> lowQueue = new LinkedList<>();
    private final Queue<User> normalQueue = new LinkedList<>();
    private final Queue<User> highQueue = new LinkedList<>();

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    private OnlineUserManager onlineUserManager;

    @Resource
    private RoomManager roomManager;

    public Matcher() {
        Thread t1 = new Thread(() -> {
            while(true) {
                handlerMatch(lowQueue);
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            while(true) {
                handlerMatch(normalQueue);
            }
        });
        t2.start();

        Thread t3 = new Thread(() -> {
            while(true) {
                handlerMatch(highQueue);
            }
        });
        t3.start();
    }

    private void handlerMatch(Queue<User> matchQueue) {
        synchronized (matchQueue) {
            try {
                while(matchQueue.size() < 2) {
                    matchQueue.wait();
                }
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();
                log.info("匹配成功：" + player1.getUsername() + " vs " + player2.getUsername());

                WebSocketSession session1 = onlineUserManager.getSessionFromGameHall(player1.getId());
                WebSocketSession session2 = onlineUserManager.getSessionFromGameHall(player2.getId());

                // 极端情况判定
                if (session1 == null) {
                    matchQueue.offer(player2);
                    return;
                }
                if (session2 == null) {
                    matchQueue.offer(player1);
                    return;
                }
                if (session1 == session2) {
                    matchQueue.offer(player1);
                    return;
                }

                // 放入游戏房间
                roomManager.add(new Room(), player1.getId(), player2.getId());

                // 通知匹配成功
                MatchResponse response1 = new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response1)));

                MatchResponse response2 = new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response2)));
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    }

    public void add(User user) {
        if(user.getScore() < 2000) {
            synchronized (lowQueue) {
                lowQueue.offer(user);
                lowQueue.notify();
            }
            log.info(user.getUsername() + " into low queue");
        } else if(user.getScore() < 3000) {
            synchronized (normalQueue) {
                normalQueue.offer(user);
                normalQueue.notify();
            }
            log.info(user.getUsername() + " into normal queue");
        } else {
            synchronized (highQueue) {
                highQueue.offer(user);
                highQueue.notify();
            }
            log.info(user.getUsername() + " into high queue");
        }
    }

    public void remove(User user) {
        if(user.getScore() < 2000) {
            synchronized (lowQueue) {
                lowQueue.remove(user);
            }
            log.info(user.getUsername() + " out of low queue");
        } else if(user.getScore() < 3000) {
            synchronized (normalQueue) {
                normalQueue.remove(user);
            }
            log.info(user.getUsername() + " out of normal queue");
        } else {
            synchronized (highQueue) {
                highQueue.remove(user);
            }
            log.info(user.getUsername() + " out of high queue");
        }
    }
}
